
#include "Entity.h"
#include "Engine.h"
//#include "boost/Thread/Thread.hpp"

bool Geometry::updateNormals = true;
bool Geometry::updateBillboards = true;
vector<Line> Geometry::normals;

//
// Constructor
//

Geometry::Geometry(Entity *_parent)
{
	parent = _parent;
	texture = 0;

	isBillboardGeom = false;
	isSubdivisionGeom = false;
	isTerrainGeom = false;
}

//
// Destructor
//

Geometry::~Geometry()
{
	mesh.CleanUp();
}

//
// Render
//

void Geometry::Render()
{
	// Loads the texture (if exists)
	#ifdef USE_TEX
	if(texture) texture->Load();
	else Texture::Clear();
	#endif

	// Calls Geometry specific rendering
	if(!isBillboardGeom)
		_Render(engine.RenderFlag());

	// Draw the normals
	AddNormals();
}

//
// Clear
//

void Geometry::Clear()
{
	mesh.Clear();
}

//
// CalculateTextureCoordinates
//

void Geometry::CalculateTextureCoordinates(float scale, TexCoordType type)
{
	mesh.CalculateTextureCoordinates(parent->Box(), scale, type);
}

//
// MergeDuplicateVertices
//

void Geometry::MergeDuplicateVertices()
{
	mesh.MergeDuplicateVertices();
}

//
// CalculateVertexNormals
//

void Geometry::CalculateVertexNormals()
{
	mesh.CalculateVertexNormals();
}

//
// LoadTexture
//

void Geometry::LoadTexture(TCHAR *fileName)
{
	texture = tManager->CreateTexture(fileName);
}

void Geometry::LoadTexture(TCHAR *fileName, Color alpha)
{
	texture = tManager->CreateTexture(fileName, alpha);
}

//
// Write
//

void Geometry::Write(FileStream &file)
{
	if(file.IsBinary())
	{
		if(texture)
		{
			file.WriteFlag(true);
			file.Write(((char*)texture->fileName), sizeof(TCHAR) * 60);
		}
		else file.WriteFlag(false);
		mesh.Write(file);
	}
	else
	{
		file.oFile << "Geometry\n";
		file.oFile << "{\n";
		if(texture) file.oFile << "Texture: " << texture->fileName << "\n";
		mesh.Write(file);
		file.oFile << "}\n";
	}
}

//
// Read
//

void Geometry::Read(FileStream &file)
{
	if(file.IsBinary())
	{
		//MessageBox(NULL, L"Reading Geometry", L"Read Geometry", 0);
		if(file.ReadFlag())
		{
			TCHAR str[60];
			file.Read(((char*)str), sizeof(TCHAR) * 60);
			LoadTexture(str);
		}
		mesh.Read(file);
	}
	else
	{
		/*file << "Geometry\n";
		file << "{\n";
		if(texture) file << "Texture: " << texture->fileName << "\n";
		mesh.Write(file, false);
		file << "}\n";*/
	}
}

//
// AddNormals
//

void Geometry::AddNormals()
{
	if(updateNormals)
	{
		uint s = normals.size();
		uint vSize = mesh.vertices.size();
		if(vSize < 20000)
		{
			normals.resize(s + vSize);

			for(uint i = 0; i < vSize; ++i)
				normals[s+i].Set(mesh.vertices[i].position, 
												 mesh.vertices[i].position + mesh.vertices[i].normal * NORMAL_MODIFIER);
		}
	}
}

//
// DrawGrid
//

void Geometry::_DrawGrid(Mesh *m, uint width, uint height, float size, const Real3 &center)
{
	Real3 p = Real3(width*size*-0.5f, 0.0f, height*size*-0.5f) + center;
	Real2 t(0.0f, 0.0f);

	for(uint i = 0; i < width + 1; ++i)
	{
		p.z = height*size*-0.5f + center.z;
		t.v = 0.0f;

		for(uint j = 0; j < height + 1; ++j)
		{
			m->AddVertex(p, Real3(0.0f, 1.0f, 0.0f), t);

			t.v += 0.10f;
			p.z += size;
		}

		t.u += 0.10f;
		p.x += size;
	}

	for(uint i = 0; i < width; ++i)
	{
		for(uint j = 0; j < height; ++j)
		{
			uint a = j + i * (height+1);	
			uint b = a + 1;	
			uint c = a + height + 1;	
			uint d = a + height + 2;	

			m->AddQuad(a, b, d, c);
		}
	}
}

//
// CalculateBBox
//

void Geometry::CalculateBBox()
{
	mesh.CalculateBBox(parent->Box());
}

void Geometry::CalculateBBoxOctree()
{
	mesh.CalculateBBoxOctree(parent);
}

//
// Rotate
//

void Geometry::Rotate(const D3DXMATRIX *rotation)
{
	mesh.RotateVertices(rotation);
}